/*
 * MainWindow.cs - Wordtrainer
 * 
 * Copyright (C) 1998-2008 Markus Kilås
 *               
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 *
 * Authors:
 *   Markus Kilås <markus@markuspage.com>
 */

using System;
using Gtk;
using WtSharp;
using System.Collections;
using System.Threading;
using System.Media;
using System.IO;
using Gdk;
using Mono.Unix;

public partial class MainWindow: Gtk.Window, WtSharp.IPractiseListener
{	
	// Global
	private Printing m_printing;
	private WtDocument m_document = new WtDocument();
	private IFileHandler m_FileHandler;
	private PageSettings m_PageSettings;
	private const int NUM_RECENT_FILES = 4;
	
	// Edit
	private EditForm editForm;
	
	// Settings
	WtSettings m_Settings = new WtSettings();
	SpecialCharacters m_SpecialChars = new SpecialCharacters();
	private ArrayList m_RecentFiles = new ArrayList();
	private SettingsForm settingsForm;
	
	// Practise
	Practise practise = new Practise();
	PractiseForm practiseForm;
	
	
	public MainWindow (string[] args): base (Gtk.WindowType.Toplevel)
	{
		m_printing = new GtkPrinting();
		m_PageSettings = new PageSettings();
		
		// GUI
		Build ();
		
		// Practise
		practiseForm = new PractiseForm(practise, m_SpecialChars);
		practiseBox.Add(practiseForm);
		practise.form = practiseForm;
		practise.listener = this;

		// Settings
		settingsForm = new SettingsForm(this, m_Settings, m_SpecialChars);
		settingsBox.Add(settingsForm);
		
		// Edit
		editForm = new EditForm(this, m_Settings, m_SpecialChars);
		editBox.Add(editForm);
		
		// Toolbar
		SetToolbarText2("");
		ToolbarLabel3.Text = "\u00a9 Markus Kil\u00e5s";		
		notebook1.ShowTabs = false;
		notebook1.CurrentPage = 1;
		toolbarRadioButtonEdit.Active = true;
		
		// Black box
		eventbox1.ModifyBg(Gtk.StateType.Normal, new Gdk.Color(0,0,0));
		
		// Settings
		LoadSettings();
		UpdateRecentFiles();
		
		// Event handlers
		this.DeleteEvent += OnDelete;
		
		// Document	
		NewDocument();
		
		// Open document from command line
		if(args.Length > 0)
			OpenDocument(args[0], null);
		
		// Display TipDialog
		if(m_Settings.GetBool("ShowTipAtStartup", false))
		{
			TipDialog tip = new TipDialog();
			tip.Modal = true;
			tip.ShowTipAtStartup = true;
			tip.Run();
			m_Settings.SetValue("ShowTipAtStartUp", tip.ShowTipAtStartup);
		}
	}
	
	private void LoadSettings()
	{
		m_SpecialChars.Char1 = m_Settings.GetString("Special1", m_SpecialChars.Char1);
		m_SpecialChars.Char2 = m_Settings.GetString("Special2", m_SpecialChars.Char2);
		m_SpecialChars.Char3 = m_Settings.GetString("Special3", m_SpecialChars.Char3);
		m_SpecialChars.Char4 = m_Settings.GetString("Special4", m_SpecialChars.Char4);
		
		// Page Settings
		object pageSettings = m_Settings.GetObject("PageSettings");
		if(pageSettings != null)
			m_PageSettings = (PageSettings)pageSettings;
		
		// Recent files
		for(int i = 0; i < NUM_RECENT_FILES; i++)
		{
			string recent = m_Settings.GetString("RecentFile"+i, null);
			if(recent != null)
				m_RecentFiles.Add(recent);
		}
	}
		
	private bool NewDocument()
	{
		if(!CloseDocument())
			return false;
		
		m_document.Info["OWNER"] = m_Settings.GetString("Name", "");
		
		settingsForm.Document = m_document;
		DocumentChanged(false);
		
		editForm.DocumentChanged(m_document);
		return true;
	}
	
	public FileChooserDialog CreateOpenDialog()
	{
		FileChooserDialog fc = new Gtk.FileChooserDialog(Catalog.GetString("Open"),
		                                                     this,
		                                                     FileChooserAction.Open,
		                                                     "Cancel",ResponseType.Cancel,
		                                                     "Open",ResponseType.Accept);
		
		foreach(FileFilter filter in FileHandlerFactory.Instance.FileFilters) 
		{
			fc.AddFilter(filter);
		}
		
		return fc;
	}
	
	public FileChooserDialog CreateSaveAsDialog()
	{
		Gtk.FileChooserDialog fc = new Gtk.FileChooserDialog(Catalog.GetString("Save As"),
	                                         this,
	                                         FileChooserAction.Save,
                                            "Cancel",ResponseType.Cancel,
                                            "Save",ResponseType.Accept);
		
		fc.DoOverwriteConfirmation = true;
		
		foreach(FileFilter filter in FileHandlerFactory.Instance.FileFilters) 
		{
			fc.AddFilter(filter);
		}
					
		return fc;
	}
	
	private void OpenDocument(string fileName, FileFilter filter)
	{
		if(!NewDocument())
			return;
		
		IFileHandler handler = FileHandlerFactory.Instance.GetFileHandler(fileName, filter);
		m_document = handler.Open(fileName);
		m_FileHandler = handler;
		
		settingsForm.Document = m_document;			
		DocumentChanged(false);
		editForm.DocumentChanged(m_document); //UpdateTitles();
		//populateList();
	}
	
	private bool Save()
	{
		if(m_document.New)
			return SaveAs();
		else
			m_FileHandler.Save(m_document, m_document.FileName);
		
		DocumentChanged(false);
		return true;
	}

	private bool SaveAs()
	{
		Gtk.FileChooserDialog fc = CreateSaveAsDialog();
		
		if(fc.Run() != (int)ResponseType.Accept)
		{
			fc.Destroy();
			return false;
		}
		
		IFileHandler fileHandler = FileHandlerFactory.Instance.GetFileHandler(fc.Filename, fc.Filter);
		fileHandler.Save(m_document, fc.Filename);
		fc.Destroy();
		DocumentChanged(false);
		return true;
	}

	private void SetBlackLabelText(string text)
	{
		BlackLabel.Markup = "<span color=\"blue\" weight=\"bold\">"+text+"</span>";
	}
	
	private void ExitApplication()
	{
		if(CloseDocument())
		{
			SaveSettings();
			Application.Quit();
		}
	}
	
	private void UpdateRecentFiles()
	{
		if(m_RecentFiles.Count > 0)
		{
			menuFileRecent1.Sensitive = true;
			menuFileRecent1.Label = "_1. " + m_RecentFiles[0];
			if(m_RecentFiles.Count > 1)
			{
				menuFileRecent2.Sensitive = true;
				menuFileRecent2.Label = "_2. " + m_RecentFiles[1];
				if(m_RecentFiles.Count > 2)
				{
					menuFileRecent3.Sensitive = true;
					menuFileRecent3.Label = "_3. " + m_RecentFiles[2];
					if(m_RecentFiles.Count > 3)
					{
						menuFileRecent4.Sensitive = true;
						menuFileRecent4.Label = "_4. " + m_RecentFiles[3];
					}
				}
			}
		}				
	}
	
	private void SaveSettings()
	{
		m_Settings.SetValue("Special1", m_SpecialChars.Char1);
		m_Settings.SetValue("Special2", m_SpecialChars.Char2);
		m_Settings.SetValue("Special3", m_SpecialChars.Char3);
		m_Settings.SetValue("Special4", m_SpecialChars.Char4);
		
		for(int i = 0; i < NUM_RECENT_FILES && i < m_RecentFiles.Count; i++)
		{
			m_Settings.SetValue("RecentFile"+i, m_RecentFiles[i]);
		}
		
		settingsForm.SaveSettings();
		
		m_Settings.Save();
	}

	protected virtual void OnMenuFileNewActivated (object sender, System.EventArgs e)
	{
		NewDocument();
	}
	
	protected virtual void OnMenuFileOpenActivated (object sender, System.EventArgs e)
	{	
		FileChooserDialog fc = CreateOpenDialog();
		
		if(fc.Run() == (int)ResponseType.Accept)
		{	
			OpenDocument(fc.Filename, fc.Filter);
		}
		fc.Destroy();
		
	}
	
	protected virtual void OnMenuFileSaveActivated (object sender, System.EventArgs e)
	{
		if(m_document.New)
		{
			SaveAs();
			return;
		}
		m_FileHandler.Save(m_document, m_document.FileName);
		DocumentChanged(false);
	}
	
	protected virtual void OnMenuFileEditActivated (object sender, System.EventArgs e)
	{
		toolbarRadioButtonEdit.Active = true;
	}

	protected virtual void OnMenuFileSettingsActivated (object sender, System.EventArgs e)
	{
		toolbarRadioButtonSettings.Active = true;
	}
	
	protected virtual void OnMenuFileExitActivated (object sender, System.EventArgs e)
	{
		ExitApplication();
	}
	
	void OnDelete (object o, DeleteEventArgs e)
	{
		if(!CloseDocument())
		{
			e.RetVal = true;	// To keep window from closing	
		}
		else
		{
			SaveSettings();
			Application.Quit();
		}
	}

	protected virtual void OnMenuEditAddActivated (object sender, System.EventArgs e)
	{
		editForm.MenuEditAddActivated();
	}
	
	public void DocumentChanged(bool changed)
	{
		m_document.Changed = changed;
		Title = m_document.FileTitle + (changed ? "*" : "") + " - " + WtSharp.AboutDialog.LONG_TITLE;
	}
	
	protected virtual void OnMenuEditNewActivated (object sender, System.EventArgs e)
	{
		editForm.MenuEditNewActivated();
	}

	protected virtual void OnMenuEditDeleteActivated (object sender, System.EventArgs e)
	{
		editForm.MenuEditDeleteActivated();
	}
	
	protected virtual void OnAnswerEnterNotifyEvent (object o, Gtk.EnterNotifyEventArgs args)
	{
		Console.WriteLine(args);
	}
	
	private bool CloseDocument()
	{
		if(m_document.Changed)
		{
			MessageDialog md = new MessageDialog (this, 
                                      DialogFlags.DestroyWithParent,
			                          MessageType.Question, 
                                      ButtonsType.YesNo, Catalog.GetString("Save file first?"));
     
			ResponseType result = (ResponseType)md.Run ();
			md.Destroy();
			if(result == ResponseType.Yes)
			{
				if(!Save())
					return false;
			}
			
		}
		if(!m_document.New)
		{
			AddToRecentFiles(m_document.FileName);
			UpdateRecentFiles();
		}
		m_document.Close();
		toolbarRadioButtonEdit.Active = true;
		editForm.DocumentChanged(m_document);
		return true;
	}
	
	private void AddToRecentFiles(string filePath)
	{
		// Place first
		m_RecentFiles.Insert(0, filePath);
		
		// Remove the other copy if one
		for(int i = 1; i < m_RecentFiles.Count; i++)
		{
			if(filePath.Equals(m_RecentFiles[i]))
			{
				m_RecentFiles.RemoveAt(i);
				return;
			}
		}
	}
	
	public void SetToolbarText1(string text)
	{
		toolbarLabel1.Text = text;
	}
	
	public void SetToolbarText2(string text)
	{
		toolbarLabel2.Text = text;
	}

	protected virtual void OnMenuEditFindActivated (object sender, System.EventArgs e)
	{
		editForm.MenuEditFindActivated();
	}

	protected virtual void OnMenuEditImportActivated (object sender, System.EventArgs e)
	{
		editForm.MenuEditImportActivated();
	}

	protected virtual void OnMenuFilePageSetupActivated (object sender, System.EventArgs e)
	{
		settingsForm.PageSetupDialog();
	}

	protected virtual void OnMenuFilePrintActivated (object sender, System.EventArgs e)
	{
		m_printing.DoPrint(m_document, m_PageSettings, this);
	}

	protected virtual void OnMenuFilePropertiesActivated (object sender, System.EventArgs e)
	{
		PropertiesDialog dlg = new PropertiesDialog(this, m_document);
		dlg.Run();
	}

	protected virtual void OnMenuFileSaveAsActivated (object sender, System.EventArgs e)
	{
		SaveAs();
	}

	protected virtual void OnToolbarRadioButtonPractiseActivated (object sender, System.EventArgs e)
	{
		if(toolbarRadioButtonPractise.CurrentValue != toolbarRadioButtonPractise.Value)
			return;
		
		Practise();
	}
	
	private void Practise()
	{
		settingsForm.SaveSettings();
		
		if(m_document.Words.Count < 1)
		{
			MessageDialog md = new MessageDialog (this, 
                                      DialogFlags.DestroyWithParent,
			                          MessageType.Error, 
                                      ButtonsType.Ok, Catalog.GetString("You must write some words before you can practising them!\n\nWrite some words or open an existing list."));
			md.Run();
			md.Destroy();
			toolbarRadioButtonEdit.Active = true;
			return;
		}
		
		PractiseDialog dlg = new PractiseDialog(this);
		dlg.Run();
		
		if(dlg.Selected == PractiseDialog.CANCEL)
		{
			toolbarRadioButtonEdit.Active = true;
			return;
		}
		else
			practise.m_PractiseInfo = new PractiseInfo(m_document.Words.Count, dlg.Selected == PractiseDialog.FOREIGN);
		
		practise.m_PractiseWords = m_document.Words;
		
		if(!m_Settings.GetBool("PractiseAll"))
		{
			int max = m_Settings.GetIntFromString("PractiseMaxNum");
			practise.m_PractiseWords = practise.m_PractiseWords.GetRange(0, System.Math.Min(max, practise.m_PractiseWords.Count));
			practise.m_PractiseInfo.WordCount = practise.m_PractiseWords.Count;
		}

		notebook1.CurrentPage = 0;
		SetBlackLabelText(Catalog.GetString("Practise"));
		menuEdit.Visible = false;
		practise.InstantCorrection = m_Settings.GetBool("InstantCorrection", false);
		practise.Document = m_document;
		practise.m_bMixWords = m_Settings.GetBool("MixWords", true); //checkbuttonSettingsMix.Active;
		practise.m_bCaseSensitive = m_Settings.GetBool("CaseSensitive", false);
		practise.m_nPauseTime = (uint)(Double.Parse(m_Settings.GetString("PauseTime", ""+0.8))*1000.0); //(uint)(Double.Parse(entrySettingsPause.Text)*1000.0);
		practise.m_bPlayWrong = m_Settings.GetBool("PlayAtWrong", false); //checkbuttonSettingsWrong.Active;
		practise.m_bPlayRight = m_Settings.GetBool("PlayAtRight", false); //checkbuttonSettingsRight.Active;
		practise.m_RightSoundFile = m_Settings.GetString("RightSound", ""); //entrySettingsRightSound.Text;
		practise.m_WrongSoundFile = m_Settings.GetString("WrongSound", ""); //entrySettingsWrongSound.Text;
		practise.StartPractise();
	}
	
	protected virtual void OnToolbarRadioButtonEditActivated (object sender, System.EventArgs e)
	{
		settingsForm.SaveSettings();
		notebook1.CurrentPage = 1;
		SetBlackLabelText(Catalog.GetString("Edit"));
		menuEdit.Visible = true;
		editForm.Activated();
	}

	protected virtual void OnToolbarRadioButtonSettingsActivated (object sender, System.EventArgs e)
	{
		notebook1.CurrentPage = 2;
		SetBlackLabelText(Catalog.GetString("Settings"));
		menuEdit.Visible = false;
		SetToolbarText1(Catalog.GetString("Settings"));
	}

	protected virtual void OnMenuPractiseStartActivated (object sender, System.EventArgs e)
	{
		toolbarRadioButtonPractise.Active = true;
	}

	protected virtual void OnMenuViewToolbarLabelsActivated (object sender, System.EventArgs e)
	{
		toolbar1.ToolbarStyle = menuViewToolbarLabels.Active ? ToolbarStyle.Both : ToolbarStyle.Icons;
	}

	protected virtual void OnMenuHelpTipActivated (object sender, System.EventArgs e)
	{
		TipDialog tip = new TipDialog();
		tip.Modal = true;
		tip.ShowTipAtStartup = m_Settings.GetBool("ShowTipAtStartup", false);
		tip.Run();
		m_Settings.SetValue("ShowTipAtStartup", tip.ShowTipAtStartup);
	}

	// This method have had some problems.
	// See: http://code.google.com/p/wordtrainer/issues/detail?id=1
	protected virtual void OnMenuHelpHelpActivated (object sender, System.EventArgs e)
	{	
		string exeFilename = System.Reflection.Assembly.GetExecutingAssembly().Location;
		string appPath = exeFilename.Substring(0, exeFilename.LastIndexOf(System.IO.Path.DirectorySeparatorChar)+1);
		
		// Try1:
		string url = "file://"+appPath+"help"+System.IO.Path.DirectorySeparatorChar+"index.html";
		Console.WriteLine("-- Trying URL: "+url);	   
		try
		{
			System.Diagnostics.Process.Start(url);
		}
		catch(Exception ex)
		{
			Console.WriteLine("Ex:"+ex);			
			Console.WriteLine(ex.StackTrace);
		}
	}

	protected virtual void OnMenuHelpWebWordtrainerActivated (object sender, System.EventArgs e)
	{
		System.Diagnostics.Process.Start("http://www.wordtrainer.net");
	}

	protected virtual void OnMenuHelpWebMarkuspageActivated (object sender, System.EventArgs e)
	{
		System.Diagnostics.Process.Start("http://www.markuspage.com");
	}

	protected virtual void OnMenuHelpAboutActivated (object sender, System.EventArgs e)
	{
		WtSharp.AboutDialog dlg = new WtSharp.AboutDialog();
		dlg.Run();
	}

	protected virtual void OnDestroyEvent (object o, Gtk.DestroyEventArgs args)
	{
		Console.WriteLine("Destroy Event");
	}

	protected virtual void OnMenuFileRecent1Activated (object sender, System.EventArgs e)
	{
		OpenDocument((string)m_RecentFiles[0], null);
	}

	protected virtual void OnMenuFileRecent2Activated (object sender, System.EventArgs e)
	{
		OpenDocument((string)m_RecentFiles[1], null);
	}

	protected virtual void OnMenuFileRecent3Activated (object sender, System.EventArgs e)
	{
		OpenDocument((string)m_RecentFiles[2], null);
	}

	protected virtual void OnMenuFileRecent4Activated (object sender, System.EventArgs e)
	{
		OpenDocument((string)m_RecentFiles[3], null);
	}

	public static void PlaySoundFile(string filename)
	{
		try 
		{
			SoundPlayer sp = new SoundPlayer(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read));
			sp.Play ();
		}
		catch(System.IO.IOException)
		{
			System.Media.SystemSounds.Beep.Play();
		}
	}
	
	public void PractiseFinished()
	{
		// Change to edit
		toolbarRadioButtonEdit.Active = true;
	}
	
	public void HelpTextChanged(string text)
	{
		SetToolbarText1(text);
	}

	protected virtual void OnButtonSettingsPageClicked (object sender, System.EventArgs e)
	{
		OnMenuFilePageSetupActivated(sender, e);
	}

}